package com.deng.eventflow.core.functions;

import com.deng.eventflow.core.Context;
import com.deng.eventflow.core.EventTracker;

import java.util.Set;

public abstract class UnaryFunction<T, U> extends Function {
    /**
     * The class of the input
     */
    private Class<T> m_inputType;

    /**
     * The class of the output
     */
    private Class<U> m_outputType;

    /**
     * Creates a new instance of an unary function
     *
     * @param t
     *          The class of the input
     * @param u
     *          The class of the output
     */
    public UnaryFunction(Class<T> t, Class<U> u)
    {
        super();
        m_inputType = t;
        m_outputType = u;
    }

    @SuppressWarnings("unchecked")
    @Override
    /* @ requires inputs.length == 1 */
    public void evaluate(/*@ non_null @*/ Object[] inputs, Object[] outputs,
            /*@ null @*/ Context context, /*@ null @*/ EventTracker tracker)
    {
        T in = (T) inputs[0];
        outputs[0] = getValue(in);
        if (tracker != null)
        {
            tracker.associateToInput(-1, 0, 0, 0, 0);
        }
    }

    /**
     * Evaluates the function
     *
     * @param x
     *          The argument
     * @return The return value of the function @ Any exception occurring during the
     *         evaluation of the underlying function
     */
    public abstract U getValue(T x);

    @Override
    public final int getInputArity()
    {
        return 1;
    }

    @Override
    public final int getOutputArity()
    {
        return 1;
    }

    @Override
    public void reset()
    {
        // Do nothing
    }

    @Override
    public UnaryFunction<T, U> duplicate(boolean with_state)
    {
        return this;
    }

    @Override
    public final void getInputTypesFor(/*@ non_null @*/ Set<Class<?>> classes, int index)
    {
        classes.add(m_inputType);
    }

    @Override
    public Class<?> getOutputTypeFor(int index)
    {
        return m_outputType;
    }
}
